/*+**************************************************************************/
/***                                                                      ***/
/***   This file is distributed under a BSD license.                      ***/
/***   See LICENSE.txt for details.                                       ***/
/***                                                                      ***/
/**************************************************************************+*/

/****************************************************************************/
/***                                                                      ***/
/***   Sprite Renderer                                                    ***/
/***                                                                      ***/
/****************************************************************************/

asc
{
  permute StaticParticlePSPerm
  {
    TEX1;
    ALPHATEST;
  };
  cbuffer StaticParticleVSPara : register(c0) : slot vs 0
  {
    row_major float4x4 mvp;     // rotation for light vector (not really needed)
    float4 di;
    float4 dj;
    float4 trans;
  };
  cbuffer StaticParticlePSPara : register(c0) : slot ps 0
  {
    float4 col;
    float4 fade0col;    
  };
}

material StaticParticleShader
{
  header
  {
    enum ExtraBits
    {
      EXTRA_TEX1      = 0x01,
      EXTRA_ALPHATEST = 0x02,
    };
    sInt Extra;
  }
  new
  {
    Extra = 0;
  }

  prepare
  {
    sInt ps=0;
    
    if (Texture[1])
    {
      ps |= 1;
    }

    if (Extra&EXTRA_ALPHATEST)
    {
      ps |= 2;
    }
    
    VertexShader = VS();    
    PixelShader = PS(ps);        
  }

  vs
  {
    asc vs_3_0                 // hlsl code
    {
      use StaticParticleVSPara;
      
      void main
      (
        in float3 in_uva : TEXCOORD1,
        in float4 in_pos : POSITION,
        in float4 in_scale : TEXCOORD0,
        in float4 in_uvrect : TEXCOORD2,
        in float1 in_fade : TEXCOORD3,
        in float4 in_color : COLOR0,
        out float4 out_uv0 : TEXCOORD0,
        out float4 out_col : COLOR0,
        out float4 out_colx : COLOR1,
        out float4 out_pos : POSITION,
      )
      {
        out_uv0.xy = in_uvrect.xy + in_uva.xy*in_uvrect.zw;
        out_uv0.zw = in_scale.zw;
        float mc = cos(in_pos.w+in_uva.z);
        float ms = sin(in_pos.w+in_uva.z);
        float3 pos = in_pos.xyz 
                   + di.xyz*in_scale.x*(ms+trans.x) + dj.xyz*in_scale.y*(mc+trans.y)
                   + di.xyz*in_scale.x*(mc+trans.z) - dj.xyz*in_scale.y*(ms+trans.w);
        out_pos = mul(float4(pos,1),mvp);
        out_col = in_fade.xxxx;
        out_colx = in_color;
      }
    }
  }

  ps 
  {
    asc ps_3_0
    {
      use StaticParticlePSPerm;
      use StaticParticlePSPara;

      sampler2D s0 : register(s0);
      sampler2D s1 : register(s1) : pif(TEX1);
      
      void main
      (
        in float4 uv0 : TEXCOORD0,
        in float4 col0 : COLOR0,
        in float4 col1 : COLOR1,
        out float4 result : COLOR0,
      )
      {
        result = tex2D(s0,uv0.xy);
        pif(TEX1)
          result *= tex2D(s1,uv0.zw);        
        result = lerp(fade0col,col*result,col0.x)*col1;
        pif(ALPHATEST)
          if (result.w<=0.0f) clip(-1);
        
      }
    }    
  }
};

/****************************************************************************/
/***                                                                      ***/
/***   Metaball Renderer                                                  ***/
/***                                                                      ***/
/****************************************************************************/

asc
{
  cbuffer MetaballsPartVSPara : register(c0) : slot vs 0
  {
    row_major float4x4 mvp;     // rotation for light vector (not really needed)
    float4 uvoffset;
    float4 ray00; 
    float4 ray01; 
    float4 ray10; 
    float4 ray11; 
    float4 CamPos;
  };
  permute MetaballsPartPSPerm
  {
    Tex;
  };
}

material MetaballsPartMtrl
{
  prepare
  {
    VertexShader = VS();
    PixelShader = PS(Texture[0]?1:0); 
  }
  
  vs
  {
    asc vs_3_0                 // hlsl code
    {
      use MetaballsPartVSPara;
      
      void main
      (
        in float3 in_pos : POSITION,
        in float3 in_part : NORMAL,
        in float2 in_uv : TEXCOORD0,
        out float4 out_uv0 : TEXCOORD0,
        out float2 out_uv1 : TEXCOORD1,
//        out float2 out_uv2 : TEXCOORD2,
        out float3 ray_start : TEXCOORD2,
        out float3 ray_dir : TEXCOORD3,
        out float4 out_pos : POSITION,
        )
      {
        out_pos = mul(float4(in_pos.xyz,1),mvp);
        out_uv0.xyz = in_part;
        out_uv0.w = out_pos.z/out_pos.w;
        out_uv1.x =  out_pos.x / out_pos.w * 0.5 + 0.5;
        out_uv1.y = -out_pos.y / out_pos.w * 0.5 + 0.5;
        ray_start = lerp(lerp(ray00,ray01,out_uv1.x),lerp(ray10,ray11,out_uv1.x),out_uv1.y);
        ray_dir = normalize(ray_start-CamPos.xyz);
        out_uv1.x += uvoffset.x;
        out_uv1.y += uvoffset.y;
//        out_uv2 = in_uv;
      }
    }
  }

  ps
  {
    asc ps_3_0
    {
      use MetaballsPartPSPerm;

      sampler2D s0 : register(s0) : pif(Tex);

      void main
      (
        in float4 uv0 : TEXCOORD0,
        in float2 uv1 : TEXCOORD1,
//        in float2 uv2 : TEXCOORD2,
        in float3 ray_start : TEXCOORD2,
        in float3 ray_dir : TEXCOORD3,

        out float4 result : COLOR0,
        out float depth : DEPTH,
      )
      {
        float r = 0.05f * 3.1;    // outer rim radius

        // nearest intersection with sphere

        float3 p1 = ray_start;
        float3 p2 = ray_start+ray_dir;
        float3 p3 = uv0.xyz;
        float a = dot(p2-p1,p2-p1);
        float b = 2*dot(p2-p1,p1-p3);
        float c = dot(p3,p3)+dot(p1,p1)-2*dot(p3,p1)-r*r;
        float ss = b*b-4*a*c;
        if(ss<=0)
        {
          result = 1;
          depth = 1;
        }
        else
        {
          float dist = (-b-sqrt(ss))/2*a * 0.02;

          result.xyz = uv0.xyz;
          result.w = dist;

          pif(Tex)
          {
            float4 old = tex2D(s0,uv1);
            if(old.w>=result.w-0.000001)
              result.w = 1;
          }    
          depth = result.w;
        }
        /*
        result = uv0;
        pif(Tex)
        {
          float4 old = tex2D(s0,uv1);
          if(old.w>=result.w-0.000000)
            result.w = 1;
        }    
        if(dot(uv2,uv2)>1)
          result.w = 1;
          */
      }
    }    
  }
};


/****************************************************************************/
asc
{
  cbuffer MetaballsTraceVSPara : register(c0) : slot vs 0
  {
    row_major float4x4 mvp;     // rotation for light vector (not really needed)
    float4 ray00; 
    float4 ray01; 
    float4 ray10; 
    float4 ray11; 
    float4 CamPos;
  };
}

material MetaballsTraceMtrl
{
  prepare
  {
    VertexShader = VS();
    PixelShader = PS(); 
  }
  
  vs
  {
    asc vs_3_0                 // hlsl code
    {
      use MetaballsTraceVSPara;
      
      void main
      (
        in float3 in_pos : POSITION,
        in float3 in_ray : NORMAL,
        in float2 in_uv0 : TEXCOORD0,
        out float2 out_uv0 : TEXCOORD0,
        out float3 ray_start : TEXCOORD1,
        out float3 ray_dir : TEXCOORD2,
        out float4 out_pos : POSITION,
      )
      {
        out_pos = mul(float4(in_pos.xyz,1),mvp);
        out_uv0 = in_uv0;
        ray_start = lerp(lerp(ray00,ray01,in_uv0.x),lerp(ray10,ray11,in_uv0.x),in_uv0.y);
        ray_dir = normalize(ray_start-CamPos.xyz);
      }
    }
  }

  ps
  {
    asc ps_3_0
    {
      sampler2D s0 : register(s0);
      sampler2D s1 : register(s1);
      sampler2D s2 : register(s2);
      sampler2D s3 : register(s3);
      sampler2D s4 : register(s4);
      sampler2D s5 : register(s5);
      sampler2D s6 : register(s6);
      sampler2D s7 : register(s7);

      void main
      (
        in float2 uv : TEXCOORD0,
        in float3 ray_start : TEXCOORD1,
        in float3 ray_dir : TEXCOORD2,
        out float4 result : COLOR0,
      )
      {
        // sample everything

        float4 sam[8];

        sam[0] = tex2D(s0,uv);
        sam[1] = tex2D(s1,uv);
        sam[2] = tex2D(s2,uv);
        sam[3] = tex2D(s3,uv);
        sam[4] = tex2D(s4,uv);
        sam[5] = tex2D(s5,uv);
        sam[6] = tex2D(s6,uv);
        sam[7] = tex2D(s7,uv);
        
        // calc range

        float dist,distf;
        float rad = 0.05f;
        float3 delta;
        float3 ray;

        ray = ray_start;

        float rim = 1/(rad*rad*3*3);
        result = 0;
        dist = 1000;

        // trace

        for(int i=0;i<10;i++)
        {
          float sum = 0;
          float mini = rad*0.5;
          for(int j=0;j<8;j++)
          {
            delta = sam[j].xyz-ray;
            float r = max(0,1/(dot(delta,delta))-rim);
            sum += r;
          }
          dist = sqrt(1/(sum+rim));
          if(dist<rad)
            mini = -1000;
          ray += ray_dir*max(mini,dist-rad)*1.0;
        }

        // final check

        if(dist*0.95<rad)
        {
          float3 norm = 0;
          for(int j=0;j<8;j++)
          {
            delta = sam[j].xyz-ray;
            float r = max(0,1/(dot(delta,delta))-rim);
            norm += r * normalize(delta);
          }
          norm = normalize(norm);
          result.r = norm.x;
          result.g = -norm.x;
          result.b = 0.5;
          result.a = 1;
        }
      }
    }    
  }
};

/****************************************************************************/
/****************************************************************************/
